﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace AusProject.OrderDataControls
{
    public partial class DataBox : UserControl
    {
        #region Title property

        protected string title;

        /// <summary>
        /// Title of data control
        /// </summary>
        public virtual string Title
        {
            get { return title; }
            set 
            {
                title = value;
                OnTitleChanged();
            }
        }

        public event EventHandler TitleChanged;

        protected void OnTitleChanged()
        {
            if (TitleChanged != null)
            {
                TitleChanged(this, new EventArgs());
            }
        }

        #endregion

        #region Mode property

        protected DataControlMode mode;

        /// <summary>
        /// Using mode of data control
        /// </summary>
        public DataControlMode Mode
        {
            get { return mode; }
            set
            {
                if (value == DataControlMode.Design)
                {
                    SetDesignMode();
                }
                else
                {
                    SetRunningMode();
                    this.Cursor = Cursors.Default;
                }
                mode = value;
            }
        }

        /// <summary>
        /// To be called when Mode property is changed
        /// Enables DesignMode's features
        /// </summary>
        protected virtual void SetDesignMode()
        {
        }

        /// <summary>
        /// To be called when Mode property is changed
        /// Enables RunningMode's features
        /// </summary>
        protected virtual void SetRunningMode()
        {
        }

        #endregion

        #region Editable property

        protected bool editable;

        /// <summary>
        /// Allows data control can be edit or not in RunningMode
        /// </summary>
        public bool Editable
        {
            get { return editable; }
            set {
                if (editable != value)
                {
                    SetEditable(value);
                    editable = value;
                }
            }
        }

        /// <summary>
        /// Enables/Disables input subcontrols of the data control
        /// </summary>
        /// <param name="value"></param>
        protected virtual void SetEditable(bool value)
        {
        }

        #endregion

        #region BorderMode property

        protected DataControlBorderMode borderMode;

        /// <summary>
        /// Indicates how to draw data control border
        /// </summary>
        public DataControlBorderMode BorderMode
        {
            get { return borderMode; }
            set {
                if (borderMode != value)
                {
                    SetBorder(value);
                    borderMode = value;
                    this.Invalidate();
                }
            }
        }

        /// <summary>
        /// Draw data control border
        /// </summary>
        /// <param name="borderMode"></param>
        protected virtual void SetBorder(DataControlBorderMode borderMode)
        {
        }

        #endregion

        #region DefaultValue property

        protected string defaultValue;

        /// <summary>
        /// The value displayed when the data control is null
        /// </summary>
        public string DefaultValue
        {
            get { return defaultValue; }
            set
            {
                SetDefaultValue(value);
                if (this.mode == DataControlMode.Design)
                {
                    Value = defaultValue;
                }
            }
        }

        /// <summary>
        /// Parse and assign values to subcontrols
        /// </summary>
        /// <param name="value"></param>
        protected virtual void SetDefaultValue(string value)
        {
            defaultValue = value;
        }

        #endregion

        #region Value property

        protected string value;

        /// <summary>
        /// The value of the data control
        /// </summary>
        public string Value
        {
            get { return GetValue(); }
            set { SetValue(value); }
        }

        /// <summary>
        /// Synthesize values of subcontrols to return
        /// </summary>
        /// <returns></returns>
        protected virtual string GetValue()
        {
            return value;
        }

        /// <summary>
        /// Parse and assign values to subcontrols
        /// </summary>
        /// <param name="value"></param>
        protected virtual void SetValue(string value)
        {
            this.value = value;
        }

        #endregion

        public int SummaryFieldId { get; set; }


        protected Pen borderPen;
        protected Pen borderDashPen;

        public DataBox()
        {
            InitializeComponent();
            borderPen = new Pen(new SolidBrush(Color.Black), 1);
            borderDashPen = new Pen(new SolidBrush(Color.Black), 1);
            borderDashPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;

            SummaryFieldId = -1;
        }


        #region Allows user to move/resize data control at runtime

        private enum EdgePos {
            None,
            Right,
            Left,
            Top,
            Bottom,
            TopLeft,
            TopRight,
            BottomLeft,
            BottomRight
        }

        private bool mMouseDown = false;
        private int mMouseDownX = 0;
        private int mMouseDownY = 0;

        private EdgePos mEdge = EdgePos.None;
        private int mWidth = 4;

        private void DataBox_MouseDown(object sender, MouseEventArgs e)
        {
            if (mode == DataControlMode.Design)
            {
                if (e.Button == System.Windows.Forms.MouseButtons.Left)
                {
                    mMouseDown = true;
                    mMouseDownX = e.X;
                    mMouseDownY = e.Y;
                }
            }
        }

        private void DataBox_MouseUp(object sender, MouseEventArgs e)
        {
            if (mode == DataControlMode.Design)
            {
                mMouseDown = false;
                this.Invalidate();
            }
        }

        private void DataBox_MouseMove(object sender, MouseEventArgs e)
        {
            if (mode == DataControlMode.Design)
            {
                if (mMouseDown)
                {
                    #region Do resize or move based on current mouse position

                    this.SuspendLayout();
                    switch (mEdge)
                    {
                        case EdgePos.None:
                            this.SetBounds(this.Left + (e.X - mMouseDownX), this.Top + (e.Y - mMouseDownY), this.Width, this.Height);
                            break;
                        case EdgePos.TopLeft:
                            if (this.Height - e.Y >= this.MinimumSize.Height)
                            {
                                this.SetBounds(this.Left, this.Top + e.Y, this.Width, this.Height - e.Y);
                            }
                            if (this.Width - e.X >= this.MinimumSize.Width)
                            {
                                this.SetBounds(this.Left + e.X, this.Top, this.Width - e.X, this.Height);
                            }
                            break;
                        case EdgePos.BottomLeft:
                            if (e.Y >= this.MinimumSize.Height)
                            {
                                this.SetBounds(this.Left, this.Top, this.Width, e.Y);
                            }
                            if (this.Width - e.X >= this.MinimumSize.Width)
                            {
                                this.SetBounds(this.Left + e.X, this.Top, this.Width - e.X, this.Height);
                            }
                            break;
                        case EdgePos.TopRight:
                            if (this.Height - e.Y >= this.MinimumSize.Height)
                            {
                                this.SetBounds(this.Left, this.Top + e.Y, this.Width, this.Height - e.Y);
                            }
                            if (e.X >= this.MinimumSize.Width)
                            {
                                this.SetBounds(this.Left, this.Top, e.X, this.Height);
                            }
                            break;
                        case EdgePos.BottomRight:
                            if (e.Y >= this.MinimumSize.Height)
                            {
                                this.SetBounds(this.Left, this.Top, this.Width, e.Y);
                            }
                            if (e.X >= this.MinimumSize.Width)
                            {
                                this.SetBounds(this.Left, this.Top, e.X, this.Height);
                            }
                            break;
                        case EdgePos.Left:
                            if (this.Width - e.X >= this.MinimumSize.Width)
                            {
                                this.SetBounds(this.Left + e.X, this.Top, this.Width - e.X, this.Height);
                            }
                            break;
                        case EdgePos.Right:
                            if (e.X >= this.MinimumSize.Width)
                            {
                                this.SetBounds(this.Left, this.Top, e.X, this.Height);
                            }
                            break;
                        case EdgePos.Top:
                            if (this.Height - e.Y >= this.MinimumSize.Height)
                            {
                                this.SetBounds(this.Left, this.Top + e.Y, this.Width, this.Height - e.Y);
                            }
                            break;
                        case EdgePos.Bottom:
                            if (e.Y >= this.MinimumSize.Height)
                            {
                                this.SetBounds(this.Left, this.Top, this.Width, e.Y);
                            }
                            break;
                    }
                    this.ResumeLayout();

                    #endregion
                }
                else
                {
                    #region Check whether mouse is at edge position and process

                    if (e.X < mWidth)
                    {
                        if (e.Y < mWidth)
                        {
                            mEdge = EdgePos.TopLeft;
                            this.Cursor = Cursors.SizeNWSE;
                        }
                        else if (e.Y > this.Height - mWidth)
                        {
                            mEdge = EdgePos.BottomLeft;
                            this.Cursor = Cursors.SizeNESW;
                        }
                        else
                        {
                            mEdge = EdgePos.Left;
                            this.Cursor = Cursors.SizeWE;
                        }
                    }
                    else if (e.X > this.Width - mWidth)
                    {
                        if (e.Y < mWidth)
                        {
                            mEdge = EdgePos.TopRight;
                            this.Cursor = Cursors.SizeNESW;
                        }
                        else if (e.Y > this.Height - mWidth)
                        {
                            mEdge = EdgePos.BottomRight;
                            this.Cursor = Cursors.SizeNWSE;
                        }
                        else
                        {
                            mEdge = EdgePos.Right;
                            this.Cursor = Cursors.SizeWE;
                        }
                    }
                    else
                    {
                        if (e.Y < mWidth)
                        {
                            mEdge = EdgePos.Top;
                            this.Cursor = Cursors.SizeNS;
                        }
                        else if (e.Y > this.Height - mWidth)
                        {
                            mEdge = EdgePos.Bottom;
                            this.Cursor = Cursors.SizeNS;
                        }
                        else
                        {
                            mEdge = EdgePos.None;
                            this.Cursor = Cursors.SizeAll;
                        }
                    }

                    #endregion
                }
            }
        }

        private void DataBox_Leave(object sender, EventArgs e)
        {
            if (mode == DataControlMode.Design)
            {
                mMouseDown = false;
                mEdge = EdgePos.None;
            }
        }

        #endregion


        public virtual DataBoxInfo ExportDataBoxInfo()
        {
            return new DataBoxInfo(-1, DataBoxType.Unspecified, Title, Editable, BorderMode, DefaultValue, Left, Top, Width, Height, null, SummaryFieldId, Value, new DataBoxFont(this.Font.Name, this.Font.Size, this.Font.Bold, this.Font.Italic));
        }
    }


    public enum DataControlMode
    {
        Design,
        Running
    }


    public enum DataControlBorderMode
    {
        None,
        Full,
        TitleOnly,
        ValueOnly
    }
}
